﻿using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;

namespace Sage.Http.Models
{
    /// <summary>
    /// 自定义的HTTP请求路由信息类，支持索引和命名参数占位符
    /// </summary>
    public partial class HttpRouteInfo
    {
        /// <summary>
        /// URL 模板，支持两种占位符格式:
        /// 1. 索引格式: "/api/users/{0}/orders/{1}"
        /// 2. 命名格式: "/api/users/{userId}/orders/{orderId}"
        /// </summary>
        public required string UrlTemplate { get; init; }

        /// <summary>
        /// HTTP 请求方法，如 GET、POST 等。
        /// </summary>
        public required HttpMethod Method { get; init; }

        /// <summary>
        /// 路由描述，可选。
        /// </summary>
        public string? Description { get; init; }

        /// <summary>
        /// 完整 URL，在调用BuildUrl等方法后会生成完整Url,包含路径参数等。
        /// </summary>
        public string? Url { get; private set; }

        /// <summary>
        /// 使用路径参数构建完整的 URL，适用于索引占位符格式 {0}, {1}
        /// </summary>
        /// <param name="pathParams">路径参数数组。</param>
        /// <returns>包含生成的 URL 的新的 HttpRouteInfo 实例。</returns>
        /// <exception cref="InvalidOperationException">UrlTemplate为空时抛出</exception>
        /// <exception cref="FormatException">格式化URL失败时抛出</exception>
        public HttpRouteInfo BuildUrl(params object[] pathParams)
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");

            try
            {
                // 使用 string.Format 替换 URL 模板中的占位符
                string url = string.Format(UrlTemplate, pathParams);

                // 返回新的 HttpRouteInfo 实例，包含生成的 URL
                return new HttpRouteInfo
                {
                    UrlTemplate = UrlTemplate,
                    Method = Method,
                    Description = Description,
                    Url = url
                };
            }
            catch (FormatException ex)
            {
                throw new FormatException($"URL模板格式错误或参数不匹配: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 按顺序替换命名占位符，适用于 {name}, {id} 格式
        /// </summary>
        /// <param name="pathParams">路径参数数组，按照占位符在URL中出现的顺序提供</param>
        /// <returns>包含生成的URL的新的HttpRouteInfo实例</returns>
        public HttpRouteInfo BuildUrlByPosition(params object[] pathParams)
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");

            // 提取所有命名占位符
            var placeholders = new List<string>();
            var matches = UrlWithRegex().Matches(UrlTemplate);

            foreach (Match match in matches)
            {
                // 获取占位符名称
                string placeholder = match.Groups[1].Value;
                placeholders.Add(placeholder);
            }

            // 检查参数数量
            if (pathParams.Length != placeholders.Count)
            {
                throw new ArgumentException(
                    $"参数数量与占位符数量不匹配。需要 {placeholders.Count} 个参数，但提供了 {pathParams.Length} 个。");
            }

            // 按顺序替换
            string result = UrlTemplate;
            for (int i = 0; i < placeholders.Count; i++)
            {
                result = result.Replace($"{{{placeholders[i]}}}", pathParams[i]?.ToString() ?? string.Empty);
            }

            return new HttpRouteInfo
            {
                UrlTemplate = UrlTemplate,
                Method = Method,
                Description = Description,
                Url = result
            };
        }

        /// <summary>
        /// 使用命名参数构建URL，适用于命名占位符格式 {name}, {id}
        /// </summary>
        /// <param name="parameters">包含参数的对象，属性名匹配占位符名称</param>
        /// <returns>包含生成的 URL 的新的 HttpRouteInfo 实例</returns>
        /// <exception cref="InvalidOperationException">UrlTemplate为空时抛出</exception>
        /// <exception cref="ArgumentNullException">parameters为null时抛出</exception>
        /// <remarks>此方法使用反射，可能不兼容AOT编译</remarks>
        [RequiresUnreferencedCode("反射访问对象属性在AOT环境中可能被裁剪")]
        [RequiresDynamicCode("反射访问对象属性可能需要动态代码生成")]
        public HttpRouteInfo BuildUrlWithParams(object parameters)
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");
            ArgumentNullException.ThrowIfNull(parameters);

            string url = UrlTemplate;

            // 获取对象的所有属性
            var properties = parameters.GetType().GetProperties();
            foreach (var prop in properties)
            {
                var value = prop.GetValue(parameters)?.ToString() ?? string.Empty;
                url = url.Replace($"{{{prop.Name}}}", value);
            }

            return new HttpRouteInfo
            {
                UrlTemplate = UrlTemplate,
                Method = Method,
                Description = Description,
                Url = url
            };
        }

        /// <summary>
        /// 使用泛型参数构建URL，适用于命名占位符格式 {name}, {id}，更兼容AOT编译
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="parameters">包含参数的强类型对象</param>
        /// <returns>包含生成的 URL 的新的 HttpRouteInfo 实例</returns>
        public HttpRouteInfo BuildUrlWithParams<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(T parameters) where T : class
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");
            ArgumentNullException.ThrowIfNull(parameters);

            string url = UrlTemplate;

            // 使用泛型类型信息获取属性
            var properties = typeof(T).GetProperties();
            foreach (var prop in properties)
            {
                var value = prop.GetValue(parameters)?.ToString() ?? string.Empty;
                url = url.Replace($"{{{prop.Name}}}", value);
            }

            return new HttpRouteInfo
            {
                UrlTemplate = UrlTemplate,
                Method = Method,
                Description = Description,
                Url = url
            };
        }

        /// <summary>
        /// 使用字典构建URL，适用于命名占位符格式 {name}, {id}，完全兼容AOT编译
        /// </summary>
        /// <param name="parameters">参数字典，键为参数名，值为参数值</param>
        /// <returns>包含生成的 URL 的新的 HttpRouteInfo 实例</returns>
        /// <exception cref="InvalidOperationException">UrlTemplate为空时抛出</exception>
        /// <exception cref="ArgumentNullException">parameters为null时抛出</exception>
        public HttpRouteInfo BuildUrlFromDictionary(IDictionary<string, object> parameters)
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");
            ArgumentNullException.ThrowIfNull(parameters);

            string url = UrlTemplate;

            // 替换所有命名参数
            foreach (var param in parameters)
            {
                url = url.Replace($"{{{param.Key}}}", param.Value?.ToString() ?? string.Empty);
            }

            return new HttpRouteInfo
            {
                UrlTemplate = UrlTemplate,
                Method = Method,
                Description = Description,
                Url = url
            };
        }

        /// <summary>
        /// 使用正则表达式模式更精确地替换命名占位符
        /// </summary>
        /// <param name="parameters">参数字典</param>
        /// <returns>包含生成的 URL 的新的 HttpRouteInfo 实例</returns>
        public HttpRouteInfo BuildUrlWithRegex(IDictionary<string, object> parameters)
        {
            if (string.IsNullOrEmpty(UrlTemplate))
                throw new InvalidOperationException("UrlTemplate cannot be null or empty.");
            ArgumentNullException.ThrowIfNull(parameters);

            // 使用正则表达式精确匹配 {name} 形式的占位符
            string url = UrlWithRegex().Replace(UrlTemplate, match =>
            {
                string paramName = match.Groups[1].Value;
                if (parameters.TryGetValue(paramName, out var value))
                {
                    return value?.ToString() ?? string.Empty;
                }
                // 未找到匹配参数，保留原占位符
                return match.Value;
            });

            return new HttpRouteInfo
            {
                UrlTemplate = UrlTemplate,
                Method = Method,
                Description = Description,
                Url = url
            };
        }

        [GeneratedRegex(@"\{([^{}]+)\}")]
        private static partial Regex UrlWithRegex();
    }
}
